/*
 * @Author: wuqingchun
 * @Date: 2024-04-26 17:06:48
 * @Description: CAS 测试
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-05-08 11:30:50
 */

#include <iostream>
#include <atomic>
#include <thread>

#include "ring_buffer.h"

int my_compare_and_swap(int* piValue, int iDesiredValue, int iNewValue)
{
    int iOldValue = *piValue;
    
    if (iOldValue == iDesiredValue)
    {
        *piValue = iNewValue;
    }

    return iOldValue;
}

bool my_compare_and_swap_v2(int* piValue, int iDesiredValue, int iNewValue)
{
    if (*piValue == iDesiredValue)
    {
        *piValue = iNewValue;
        return true;
    }

    return false;
}

void test_cas()
{
    int iValue = 100;

    // 自己实现的 CAS 
    int iRet = my_compare_and_swap(&iValue, 100, 101);
    std::cout << "oldvalue1: " << iRet << ", iValue: " << iValue << std::endl;
    iRet  = my_compare_and_swap(&iValue, 100, 101);
    std::cout << "oldvalue2: " << iRet << ", iValue: " << iValue << std::endl;

    std::cout << "swap1: " << my_compare_and_swap_v2(&iValue, 101, 102);
    std::cout << ", iValue: " << iValue << std::endl;
    std::cout << "swap2: " << my_compare_and_swap_v2(&iValue, 101, 102);
    std::cout << ", iValue: " << iValue << std::endl;

    // GCC的CAS，GCC4.1+版本中支持CAS的原子操作。
    iRet = __sync_val_compare_and_swap(&iValue, 102, 103);
    std::cout << "oldvalue3: " << iRet << ", iValue: " << iValue << std::endl;
    iRet = __sync_val_compare_and_swap(&iValue, 102, 103);
    std::cout << "oldvalue4: " << iRet << ", iValue: " << iValue << std::endl;


    std::cout << "swap3: " << __sync_bool_compare_and_swap(&iValue, 103, 104);
    std::cout << ", iValue: " << iValue << std::endl;
    std::cout << "swap4: " << __sync_bool_compare_and_swap(&iValue, 103, 104);
    std::cout << ", iValue: " << iValue << std::endl;

    // C++11中的CAS，C++11中的STL中的atomic类的函数可以让你跨平台。
    std::atomic<int> atmValue {104};
    std::cout << "atomic swap1: " << atomic_compare_exchange_weak(&atmValue, &iValue, 105); 
    std::cout << ", atmValue: " << atmValue.load() << std::endl;
    std::cout << "atomic swap1: " << atomic_compare_exchange_weak(&atmValue, &iValue, 105); 
    std::cout << ", atmValue: " << atmValue.load() << std::endl;
}

void test_ring_buffer()
{
    constexpr int MAX_SIZE = 1024;
    RingBuffer<int, 4> objRingBuff;

    volatile bool bRunFlag = true;

    int* apiData = new int[MAX_SIZE];
    for (int i = 0; i < MAX_SIZE; i++)
    {
        apiData[i] = i;
    }

    std::thread objProducer([&objRingBuff, apiData](volatile bool& refRunFlag){
        int iIndex = 0;
        while (refRunFlag)
        {
            if (objRingBuff.AtmPush(apiData + iIndex))
            {
                //printf("%d:%d\n", iIndex, apiData[iIndex]);
                iIndex = (iIndex + 1) & (MAX_SIZE - 1);
            }
        } 
    }, std::ref(bRunFlag));

    std::thread objConsumer([&objRingBuff, apiData](volatile bool& refRunFlag){
        int iData = 0;

        while (refRunFlag)
        {
            const int* piData = objRingBuff.AtmPop();
            if (piData != nullptr)
            {
                //std::cout << *piData << std::endl;
                if (*piData == iData)
                {
                    iData = (iData + 1) & (MAX_SIZE - 1);
                }
                else
                {
                    std::cout << "error: " << piData << ", " << *piData << "," << iData << std::endl;
                    objRingBuff.Debug();
                    break;
                }
            }
            else
            {

            }
        } 
    }, std::ref(bRunFlag));


    while (getchar() != 'Q')
    {

    }

    bRunFlag = false;

    objProducer.join();
    objConsumer.join();
}

void test_sub(int argc, char** argv)
{
    if (argc <= 2)
    {
        printf("Usage: %s head tail\n", argv[0]);
        return;
    }

    /**
     * uiHead      uiTail            uiHead - uiTail
     *    4          0                    4
     *    0          255                  1
     *    1          254                  3
     */

    uint8_t uiHead = atoi(argv[1]);
    uint8_t uiTail = atoi(argv[2]);

    printf("uiHead - uiTail = %hhu\n", uiHead - uiTail);
}

int main(int argc, char** argv)
{
    test_cas();
    test_ring_buffer();

    //test_sub(argc, argv);

    return 0;
}